#include "Perceptron.h"

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Perceptron
 *      Method:  Perceptron
 * Description:  Constrói um perceptron passando o nº de variávies de entrada e de saída,
 *               a função de ativação e o aprendizado
 *--------------------------------------------------------------------------------------
 */
Perceptron::Perceptron(uint nInVars, uint nOutVars, ActivationPtr activation,
        LearningPtr learning, CSVFilePtr csv)
{
    this->nInVars = nInVars;
    this->nOutVars = nOutVars;

    for(uint i = 0; i < nOutVars; i++)
    {
        if(csv.get() != NULL)
            assert(csv->has());
        NeuronPtr n(new Neuron(nInVars, activation, learning, csv));
        neurons.push_back(n);
    }
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Perceptron
 *      Method:  feedforward
 * Description:  Realiza o feedforward na camada de saída
 *--------------------------------------------------------------------------------------
 */
vdoublePtr Perceptron::feedforward(vdoublePtr input)
{
    this->input = input;
    vdoublePtr output(new vdouble);

    for(uint i = 0; i < neurons.size(); i++) // Loop para cada neurônio
    {
        double out = neurons[i]->getOutput(input);
        output->push_back(out);
    }
    
    return output;
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Perceptron
 *      Method:  feedbackward
 * Description:  Realiza o feedbackward
 *--------------------------------------------------------------------------------------
 */
vdoublePtr Perceptron::feedbackward(vdoublePtr expected)
{
    vdoublePtr e(new vdouble);

    // Loop para cada neurônio
    for(uint i = 0; i < neurons.size(); i++)
        e->push_back(neurons[i]->getError(expected->at(i)));

    return e;
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Perceptron
 *      Method:  feedbackward
 * Description:  Realiza o feedbackward na camada escondida
 *--------------------------------------------------------------------------------------
 */
vdoublePtr Perceptron::feedbackward(vdoublePtr errors, vector<NeuronPtr>& nextNeurons)
{ 
    vdoublePtr e(new vdouble);

    // Loop para cada neurônio
    for(uint i = 0; i < neurons.size(); i++)
    {
        vdoublePtr weights(new vdouble);

        // Pesos das arestas que conectam o neurônio atual à próxima camada
        for(uint j = 0; j < nextNeurons.size(); j++)
            weights->push_back(nextNeurons[j]->getWeight(i));

        e->push_back(neurons[i]->getError(errors, weights));
    }

    return e;
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Perceptron
 *      Method:  updateNeurons
 * Description:  Atualiza os pesos dos neurônios
 *--------------------------------------------------------------------------------------
 */
void Perceptron::updateNeurons()
{
    for(uint i = 0; i < neurons.size(); i++)
        neurons[i]->update(input);
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Perceptron
 *      Method:  print
 * Description:  Imprime o perceptron
 *--------------------------------------------------------------------------------------
 */
void Perceptron::print()
{
    for(uint i = 0; i < nOutVars; i++)
    {
        cout << " |--> Neuron " << (i + 1) << " weights: ";
        neurons[i]->print();
        cout << endl;
    }
}

